package main

import (
    "fmt"
    "time"

    //"time"
)

// 颜色板，将print打印成特殊颜色，方便查看对应的输出结果
const (
    TextBlack = iota + 30
    TextRed
    TextGreen
    TextYellow
    TextBlue
    TextMagenta
    TextCyan
    TextWhite
)

//将说明打印成蓝色
func debug(s string) {
    fmt.Printf("\x1b[0;%dm%s\x1b[0m\n", TextBlue, s)
}

/* channel学习总结
1, make chan
1.2, Send数据
2， recv数据
3，关闭chan, 清空chan
4, 遍历Chan
5, goroutine中读写chan
6, nil chan
7, chan做为参数，意向Chan
*/

//打印一个chan的属性, len表示chan中元素的个数，cap表示容量大小
func printChan(ch chan string) {
    if ch == nil {
        fmt.Println("nil chan")
    }
    //打印chan，len表示缓冲区长度，cap表示容量
    fmt.Printf("s=%v\nlen=%d cap=%d\n", ch, len(ch), cap(ch))
    //close(ch)
}

// 读取Chan, index表示当前执行的是第几个go routine,方便debug
func readCh(ch chan string, index int) {
    //time.Sleep(time.Second)
    i := 0
    for {
        select {//select中的Case后面跟的条件必须是chan的读写操作
            case x := <-ch:
                fmt.Println(x)
                //time.Sleep(time.Second)
            default:
                fmt.Printf("waiting for send [%d]---%d\n", index, i)
                time.Sleep(time.Second)
        }
        i++
    }
}

func sendToChan(ch chan string) {
    ch <- "hello"
}
func sendString(ch chan <- string) {
    ch <- "hello"
    //fmt.Println(<-ch)//错误：invalid operation: <-ch (receive from send-only type chan<- string)
}
func recvString(ch <- chan string) {
    //ch <- "hello" //错误：invalid operation: ch <- "hello" (send to receive-only type <-chan string)
    fmt.Println(<-ch)
}


func main() {
    debug("1.1 创建一个无缓存的chan")
    ch := make(chan string) // 1.1 无缓存chan, len=0, cap=0
    printChan(ch)

    debug("1.2 向无缓存的chan写数据， 出错")
    go readCh(ch, 0) //本行注释掉，则出现错误 all goroutines are asleep，因为ch无缓存，gorouting中阻塞
    ch <- "a"              //阻塞, goroutine中读取完数据后，往下执行

    //close(ch)

    debug("1.3 创建一个有缓存的chan")
    ch1 := make(chan string, 2)
    printChan(ch1)      // len=0, cap=2

    debug("1.4 向有缓存的chan写/发送数据")
    ch1 <- "hello"      // chan : len=1, cap=2
    ch1 <- "world"      // chan : len=2, cap=2
    //ch1 <- "hi"         //阻塞, 缓冲区满了
    printChan(ch1)      // len=2, cap=2

    debug("2 读取/接收数据 <- chan")
    //s := <- ch1       //赋值读取
    fmt.Println(<-ch1) //直接打印读取结果, hello, 每次只读取一个
    fmt.Println(<-ch1) //先进先出，world

    debug("3 关闭chan")
    close(ch1)
    printChan(ch1)  // len = 0, cap  = 2
    debug("3.1 关闭chan后，再写chan")
    //ch1 <- "hi"//panic: send on closed channel

    debug("3.2 判断chan是否有关闭")
    res, ok := <- ch1 //res = “”, ok=false
    fmt.Println(res, ok)

    debug("3.3 清空数据")
    for len(ch1) > 0 {
        <-ch1
    }

    debug("3.4 判断chan是否有数据")
    if len(ch1) == 0 {
        fmt.Println("ch1已经清0")
    }

    debug("4 遍历chan")
    s1 := []byte{'a'}
    ch2 := make(chan string, 5)
    for s := 'a'; s < 'a' + 5; s++ {//先填入数据从a开始数5个字母
        s1 = append(s1, byte(s))
        ch2 <- string(s1)
    }
    j := 0
    for i := range ch2 {        // range是一个读操作，如果没有break, 则会一直读，读完后就阻塞
        fmt.Printf("[%d] = %s\n", j, i)
        j++
        if len(ch2) == 0 {      //注释本段代码，则在len==0时，继续读取，会形成阻塞
            break
        }
    }
    close(ch2)

    debug("5 go routine中读取")
    s2 := []byte{'g'}
    k := 0
    ch3 := make(chan string, 6)
    go readCh(ch3, 3)
    for k < 22 {
        k++
        s2 = append(s2, byte('g' + k))
        ch3 <- string(s2)
    }

    debug("6 nil chan")
    var chnil chan string   // 6.0.0 未初始化都是nil
    printChan(chnil)        // 6.0.1 nil的len和cap: s=<nil>, len=0, cap=0
    //close(chnil)          // 6.0.2 关闭nil出错：panic: close of nil channel
    //<- chnil              // 6.0.3 阻塞, 上面两个goroutine会一直执行
    //chnil <- "a"          // 6.0.4 阻塞, 上面两个goroutine会一直执行

    debug("6.1 向nil chan中发送数据")
    //<- (chan int)(nil)      //阻塞, 上面两个goroutine会一直执行


    debug("7 chan做为参数")  //chan是一个指针，不需要使用&方式传递
    ch7 := make(chan string, 6)
    sendToChan(ch7)
    fmt.Println(<-ch7)          // chan是一个指针

    debug("7.1 单向chan, 只发送和只接收")
    sendString(ch7)
    recvString(ch7)
}



